// This file is part of OpenMeca, an easy software to do mechanical simulation.
//
// Author(s)    :  - Damien ANDRE  <openmeca@gmail.com>
//
// Copyright (C) 2012 Damien ANDRE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.


#include <GL/glu.h>

#include "OpenMeca/Core/Drawable.hpp"
#include "OpenMeca/Core/SelectionManager.hpp"

#include "boost/serialization/export.hpp"
//Don't forget to export for dynamic serialization of child class
BOOST_CLASS_EXPORT(OpenMeca::Core::Drawable)

namespace OpenMeca
{  
  namespace Core
  {

    int Drawable::drawableItemCounter_ = 0;
    std::map<int, Drawable*> Drawable::map_ = std::map<int, Drawable*>();

    Drawable& 
    Drawable::GetDrawableItemByGLKey(int itemGLKey)
    {
      assert(map_.count(itemGLKey)==1);
      return *map_[itemGLKey];      
    }




    const std::string 
    Drawable::GetStrType() 
    {
      return "Drawable";
    }

    Drawable::Drawable(const std::string strType, QTreeWidgetItem& parent, bool isSelectable)
      :Core::UserItem(strType, parent),
       itemGLKey_(drawableItemCounter_),
       isSelectable_(isSelectable)
    {
      assert(map_.count(itemGLKey_)==0);
      map_[itemGLKey_] = this;
      drawableItemCounter_++;
    }

    Drawable::~Drawable()
    {
    }

 
    void
    Drawable::Draw(bool withName)
    {
      BeginDraw();

      if (IsSelected())
	Core::Singleton<Core::SelectionManager>::Get().GetSelectedColor().ApplyGLColor();
      else
	GetColor().ApplyGLColor();

      GetFrame().UpdateGLMatrix();

      glPushMatrix();

      if (withName == true && IsSelectable())
	glPushName(GetItemGLKey());

      glMultMatrixd(GetFrame().GetGLMatrix());
      DrawShape();

      if (withName == true && IsSelectable())
	glPopName();

      glPopMatrix();
      
      EndDraw();
    }

    unsigned int 
    Drawable::GetItemGLKey() const
    {
      return itemGLKey_;
    }

    bool 
    Drawable::IsSelectable() const
    {
      return isSelectable_;
    }




    //Static methods that draw misceallous shape
    void
    Drawable::DrawCylinder(float radius, float length, bool middlePositinning)
    {
      //Draw a cylinder along the x axis with given radius and length
      glRotatef(90., 0.0, 1.0, 0.0);
      static GLUquadric* quadric = gluNewQuadric();
      if (middlePositinning)
	glTranslatef(0.0f, 0.0f, -length/2);
      gluCylinder(quadric, radius, radius, length, 30, 1);
      glTranslatef(0.0f, 0.0f, length);
      gluDisk(quadric, 0.0, radius, 30, 1);
      glRotatef(180.0, 0.0, 1.0, 0.0);
      glTranslatef(0.0f, 0.0f, length);
      gluDisk(quadric, 0.0, radius, 30, 1);
      glTranslatef(0.0f, 0.0f, -length/2);
      glRotatef(-90.0, 0.0, 1.0, 0.0);
    }

    void
    Drawable::DrawSphere(float radius)
    {
      //Draw a cylinder along the x axis with given radius and length
      static GLUquadric* quadric = gluNewQuadric();
      gluSphere(quadric, radius, 30, 30);
    }



  }
}




